﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Migrations;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using ManagementClinic.Data.Models;

namespace ManagementClinic.Data.DataContext
{
    public class Repository<T> : IRepository<T> where T : class 
    {
        readonly DataAccessContext _dataContext;
        public Repository()
        {
            _dataContext = new DataAccessContext();
        }

        #region IRepository<T> Members

        public bool Insert(T entity)
        {
            try
            {
              _dataContext.Set<T>().Add(entity);
              _dataContext.SaveChanges();
                return true;
            }
            catch (Exception ex)
            {

                return false;
            }
           
        }
        public bool Edit(T entity)
        {
            try
            {
                _dataContext.Set<T>().AddOrUpdate(entity);
                _dataContext.SaveChanges();
                return true;
            }
            catch (Exception)
            {

                return false;
            }

        }
        public void Delete(T entity)
        {
            _dataContext.Set<T>().Remove(entity);
            _dataContext.SaveChanges();
        }
        public bool Delete(int id)
        {
            try
            {
                T entity = GetById(id);
                if (entity != null)
                {
                    _dataContext.Set<T>().Remove(entity);
                    _dataContext.SaveChanges();
                }
                return true;
            }
            catch (Exception)
            {
                return false;
            }
          
        }
        public bool DeleteAll(List<T> list )
        {
            try
            {
            _dataContext.Set<T>().RemoveRange(list);
            _dataContext.SaveChanges();
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }
        public List<T> Get(Expression<Func<T, bool>> predicate)
        {
            return _dataContext.Set<T>().Where(predicate).ToList();
        }

        public List<T> Get(Expression<Func<T, bool>> predicate, string fieldOrderBy, bool ascending)
        {
            var p = typeof (T).GetProperty(fieldOrderBy);
            var t = p.PropertyType;
            if (t == typeof (Int32))
            {
                var pe = Expression.Parameter(typeof (T), "p");
                var expr1 = Expression.Lambda<Func<T, int>>(Expression.Property(pe, fieldOrderBy), pe);
                return ascending
                    ? _dataContext.Set<T>().Where(predicate).OrderBy(expr1).ToList()
                    : _dataContext.Set<T>().Where(predicate).OrderByDescending(expr1).ToList();
            }
            else
            {
                if (t == typeof (Int32?))
                {
                    var pe = Expression.Parameter(typeof (T), "p");
                    var expr1 = Expression.Lambda<Func<T, int?>>(Expression.Property(pe, fieldOrderBy), pe);
                    return ascending
                        ? _dataContext.Set<T>().Where(predicate).OrderBy(expr1).ToList()
                        : _dataContext.Set<T>().Where(predicate).OrderByDescending(expr1).ToList();
                }
                else
                {
                    var pe = Expression.Parameter(typeof (T), "p");
                    var expr1 = Expression.Lambda<Func<T, String>>(Expression.Property(pe, fieldOrderBy), pe);
                    return ascending
                        ? _dataContext.Set<T>().Where(predicate).OrderBy(expr1).ToList()
                        : _dataContext.Set<T>().Where(predicate).OrderByDescending(expr1).ToList();
                }

            }
        }

        public List<T> Get(Expression<Func<T, bool>> predicate, string fieldOrderBy, bool ascending,int skip,int take)
        {
            var p = typeof(T).GetProperty(fieldOrderBy);
            var t = p.PropertyType;
            if (t == typeof (Int32))
            {
                var pe = Expression.Parameter(typeof (T), "p");
                var expr1 = Expression.Lambda<Func<T, int>>(Expression.Property(pe, fieldOrderBy), pe);
                return ascending ? _dataContext.Set<T>().Where(predicate).OrderBy(expr1).Skip(skip).Take(take).ToList() : _dataContext.Set<T>().Where(predicate).OrderByDescending(expr1).Skip(skip).Take(take).ToList();
            }
            else
            {
                var pe = Expression.Parameter(typeof(T), "p");
                var expr1 = Expression.Lambda<Func<T, String>>(Expression.Property(pe, fieldOrderBy), pe);
                return ascending ? _dataContext.Set<T>().Where(predicate).OrderBy(expr1).Skip(skip).Take(take).ToList() : _dataContext.Set<T>().Where(predicate).OrderByDescending(expr1).Skip(skip).Take(take).ToList();
            }

        }

        public int GetCount(Expression<Func<T, bool>> predicate)
        {
            return _dataContext.Set<T>().Where(predicate).Count();
        }
     
        public List<T> GetAll()
        {
            return _dataContext.Set<T>().ToList();
        }

        public T GetById(int id)
        {
            return _dataContext.Set<T>().Find(id);
        }

        #endregion
    }
}
